#!/usr/bin/python3
# -*- coding: utf-8 -*-

import json
from json.decoder import JSONDecodeError

from playwright.sync_api import Page
from yarl import URL

from databases.sqlite import SQLiteDB
from public.project_patch import DB, DOWNLOAD_DIR
from utils.cache_util import cache_manager
from utils.date_util import get_local_date_and_now
from utils.log import log


class Event:
    def __init__(self, page: Page):
        self.page = page
        self.page.on("dialog", self.on_load)
        self.page.on("console", self.on_console)  # 监控console输出
        self.page.on("request", self.on_request)  # 监控ajax请求
        self.page.on("response", self.on_response)  # 监控ajax请求
        self.page.on("popup", self.on_popup)
        self.page.on("crash", self.on_crash)
        self.page.on("dialog", self.on_dialog)
        self.page.on("download", self.on_download)
        self.page.on("pageerror", self.on_pageerror)
        # self.page.on("requestfailed",self.on_requestfailed)
        # self.page.on("requestfinished",self.on_requestfinished)
        self.page.on("websocket", self.on_websocket)
        # self.page.on("framenavigated", self.on_framenavigated)

    @staticmethod
    def on_load():
        """页面加载完成时触发"""
        log.info("页面加载完成")

    @staticmethod
    def on_console(console_message) -> None:
        """
        抓取console日志
        :param console_message: 可根据 type 来过滤错误信息
        :return:
        """
        if console_message.type in ["error", "trace"]:
            log.debug(f"Console 消息类型: {console_message.type}")
            log.debug(f"Console 消息内容: {console_message.text}")
            log.debug(f"错误位置: {console_message.location}")

    @staticmethod
    def on_request(request) -> None:
        """页面发出请求时触发"""
        try:
            if request.post_data_json is not None and cache_manager.get('base_url') in request.url:
                action = ""
                if "action=" in request.url:
                    action = request.url.split("action=")[-1]
                data = {
                    "url": request.url,
                    "method": request.method.lower(),
                    "headers": request.headers,
                    "post_data": request.post_data,
                    "post_data_json": request.post_data_json,
                    "action": action,
                }
                url = URL(data["url"])
                sqlite = SQLiteDB(DB)
                sqlite.insert_data(
                    table="api_request",
                    data={
                        "action": action,
                        "request_time": get_local_date_and_now(),
                        "host": url.host,
                        "url": url,
                        "method": data["method"],
                        "body": str(data["post_data_json"]["params"]),
                    },
                )
                log.debug(f"请求数据:{data}")
        except Exception:
            pass

    @staticmethod
    def on_response(response) -> None:
        """接受到响应时触发"""
        try:
            _json = response.json()
        except JSONDecodeError:
            _json = None
        except Exception:
            _json = None

        try:
            if _json is not None and cache_manager.get('base_url') in response.url:
                action = ""
                if "action=" in response.url:
                    action = response.url.split("action=")[-1]
                data = {
                    "action": action,
                    "response_time": get_local_date_and_now(),
                    "url": response.url,
                    "status": response.status,
                    "json": _json,
                }
                url = URL(data["url"])
                sqlite = SQLiteDB(DB)
                sqlite.insert_data(
                    table="api_response",
                    data={
                        "action": data["action"],
                        "response_time": data["response_time"],
                        "host": url.host,
                        "url": url,
                        "response": json.dumps(data["json"]),
                        "status_code": int(data["status"]),
                    },
                )
                log.debug(f"响应数据:{data}")
        except Exception:
            pass

    @staticmethod
    def on_requestfailed(request):
        """请求在某个时间失败时触发"""
        log.info(f"on_requestfailed请求url:{request.url},请求方法:{request.method}")

    @staticmethod
    def on_requestfinished(request):
        """当响应被下载且请求完成是触发"""
        log.info(f"on_requestfinished请求url:{request.url},请求方法:{request.method}")

    @staticmethod
    def on_popup(page):
        log.info(f"打开新页面:{page.url}")

    @staticmethod
    def on_frame_sent(frame):
        log.debug("sent", frame)

    @staticmethod
    def on_received(frame):
        log.debug("received", frame)

    @classmethod
    def on_websocket(cls, websocket):
        websocket.on("framesent", cls.on_frame_sent)  # 从此处进去可发现websocket on的event有哪些
        websocket.on("framereceived", cls.on_received)
        websocket.on("onMessage", lambda message: log.debug("message", message))

    @staticmethod
    def on_crash(exception):
        """crash 事件"""
        log.info(f"浏览器页面 crash:{str(exception)}")

    @staticmethod
    def on_dialog(dialog):
        """dialog 事件"""
        log.info(f"检测到dialog对话框: {dialog.type}")
        if dialog.type == "alert":
            log.info(f"警告消息: {dialog.message}")
            dialog.accept()  # 默认接受警告对话框
        elif dialog.type == "confirm":
            log.info(f"确认消息: {dialog.message}")
            dialog.confirm()  # 假设总是确认
        elif dialog.type == "prompt":
            log.info(f"提示消息: {dialog.message}")
            dialog.fill("User input")  # 提供一个输入值
            dialog.confirm()  # 确认输入

    @staticmethod
    def on_download(download):
        """下载事件"""
        log.info(f"下载文件: {download.url} 到:{DOWNLOAD_DIR}")

    @staticmethod
    def on_pageerror(error):
        """页面发生错误时触发"""
        log.critical(f"页面发生错误: {error.message}")

    @staticmethod
    def on_framenavigated(frame):
        """当一个框架导航到新的 URL 时发出"""
        log.debug(f"框架导航到: {frame.url}")
